package com.chuangke.common.apt;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chuangke.common.annotation.Entity;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;

import javassist.bytecode.stackmap.TypeData.ClassName;

@AutoService(Processor.class)
@SupportedAnnotationTypes("com.chuangke.common.annotation.Entity")
@SupportedSourceVersion(value = SourceVersion.RELEASE_8)
public class EntityAnnotationProcessor extends AbstractProcessor {

    private Elements elementUtils;
    private Types typeUtils;
    private Filer filer;
    private Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        elementUtils = processingEnvironment.getElementUtils();
        typeUtils = processingEnvironment.getTypeUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (set.isEmpty()) {
            return false;
        }

        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Entity.class);
        for (Element element : elements) {
            if(!(element instanceof TypeElement)){
                continue;
            }
            try {
                buildMapper(element);
                buildDao(element) ;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        return true;
    }

    private void buildMapper(Element element) throws Exception {
        String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
        String className = element.getSimpleName().toString();

        String mapperPackage = packageName.substring(0, packageName.lastIndexOf(".")) + ".dao.mapper";
        String mapperName = className + "Mapper";

        messager.printMessage(Diagnostic.Kind.NOTE, "=CkEntityProcessor=" + packageName + "/" + className);

        TypeSpec typeSpec = TypeSpec.interfaceBuilder(mapperName)
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Mapper.class)
//                .addSuperinterface(ParameterizedTypeName.get(ClassName.get(BaseMapper.class), TypeVariableName.get(packageName+"."+className)))
                .build();

        JavaFile javaFile = JavaFile.builder(mapperPackage, typeSpec)
                .build();

        // 写入
        javaFile.writeTo(filer);
    }

    private void buildDao(Element element) throws Exception {
        String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
        String className = element.getSimpleName().toString();

        String mapperPackage = packageName.substring(0, packageName.lastIndexOf(".")) + ".dao";
        String daoName = className + "Dao";

        String entityName = packageName+"."+className;
        String mapperName = mapperPackage+".mapper."+className + "Mapper";

        TypeSpec typeSpec = TypeSpec.classBuilder(daoName)
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Service.class)
//                .superclass(ParameterizedTypeName.get(ClassName.get(ServiceImpl.class), TypeVariableName.get(mapperName),TypeVariableName.get(entityName)))
                .build();

        JavaFile javaFile = JavaFile.builder(mapperPackage, typeSpec)
                .build();

        // 写入
        javaFile.writeTo(filer);
    }
}
